package com.elitel.frame.base.service.impl;

import com.elitel.common.asserts.CommonAssert;
import com.elitel.common.utils.StringUtils;
import com.elitel.frame.base.component.RedisCacheProjectService;
import com.elitel.frame.base.component.exportprojectdata.DataBaseConnInfo;
import com.elitel.frame.base.service.SysProjectService;
import com.elitel.frame.main.dao.SysProjectMapper;
import com.elitel.frame.main.dao.ext.ExtCfgDbMapper;
import com.elitel.frame.main.dao.ext.ExtSysPrjmenuMapper;
import com.elitel.frame.main.dao.ext.ExtSysPrjserviceMapper;
import com.elitel.frame.main.dao.ext.ExtSysProjectMapper;
import com.elitel.frame.main.entity.CfgDb;
import com.elitel.frame.main.entity.DataSourceType;
import com.elitel.frame.main.entity.PrjCfgDb;
import com.elitel.frame.main.entity.SysProject;
import com.elitel.frame.main.entity.ext.ExtSysProject;
import com.elitel.frame.main.entity.ext.PrjServiceExt;
import com.elitel.frame.main.entity.ext.SysProjectExt;
import com.elitel.frame.main.entity.vo.PageRequestVo;
import com.elitel.frame.main.entity.vo.PageResponseVo;
import com.elitel.frame.main.entity.vo.ZTreeDataModelVo;
import com.elitel.common.utils.SysUserUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class SysProjectServiceImpl implements SysProjectService {

    @Autowired
    private SysProjectMapper sysProjectMapper;
    @Autowired
    private ExtSysProjectMapper extSysProjectMapper;
    @Autowired
    private ExtSysPrjserviceMapper extSysPrjserviceMapper;
    @Autowired
    private ExtSysPrjmenuMapper extSysPrjmenuMapper;
    @Autowired
    private RedisCacheProjectService redisCacheProjectService;
    @Autowired
    private DataBaseConnInfo dataBaseConnInfo;
    @Autowired
    private ExtCfgDbMapper extCfgDbMapper;

    @Override
    public PageResponseVo<SysProject> getProjectList(PageRequestVo<SysProject> pr) {
        String databaseType = dataBaseConnInfo.dataBaseType;
        List<SysProject> list = new ArrayList<SysProject>();
        PageResponseVo<SysProject> responseVo = new PageResponseVo<SysProject>();
        switch (databaseType) {
            case "oracle":
            case DataSourceType.DM:
                pr.StartPage();
                list = extSysProjectMapper.getProjectByPagination(pr);
                break;
            case "mysql":
            case "sqlite":
            case "h2":
                pr.setPageNo((pr.getPageNo() - 1) * pr.getPageSize());
                list = extSysProjectMapper.getProjectByPaginationMysql(pr);
                break;
            case DataSourceType.POSTGRES:
                pr.setPageNo((pr.getPageNo() - 1) * pr.getPageSize());
                list = extSysProjectMapper.getProjectByPaginationPG(pr);
                break;
        }

        if (list != null && !list.isEmpty()) {
            List<String> pCodeList = list.stream().map(SysProject::getPcode).collect(Collectors.toList());
            // 查询数据
            List<PrjCfgDb> dbInfoList = extSysProjectMapper.selectDbInfoByPCodeList(pCodeList);
            Map<String, List<PrjCfgDb>> pcodeDbList = dbInfoList.stream().collect(Collectors.groupingBy(PrjCfgDb::getProjectCode));
            for (SysProject sysProject : list) {
                String pcode = sysProject.getPcode();
                List<PrjCfgDb> prjCfgDbs = pcodeDbList.get(pcode);
                if (prjCfgDbs != null && !prjCfgDbs.isEmpty()) {
                    String dbNames = prjCfgDbs.stream().map(CfgDb::getDbName).filter(StringUtils::isNotEmpty).collect(Collectors.joining("，"));
                    String  dbVersion = prjCfgDbs.stream().map(CfgDb::getDbVersion).filter(StringUtils::isNotEmpty).collect(Collectors.joining("，"));
                    String  dbIps = prjCfgDbs.stream().map(CfgDb::getDbIp).filter(StringUtils::isNotEmpty).collect(Collectors.joining("，"));
                    String  dbSchemas = prjCfgDbs.stream().map(CfgDb::getDbSchema).filter(StringUtils::isNotEmpty).collect(Collectors.joining("，"));
                    sysProject.setDbNames(dbNames);
                    sysProject.setDbVersion(dbVersion);
                    sysProject.setDbIp(dbIps);
                    sysProject.setDbSchema(dbSchemas);
                } else {
                    sysProject.setDbNames("");
                    sysProject.setDbVersion("");
                    sysProject.setDbIp("");
                    sysProject.setDbSchema("");
                }
            }
        }

        Long count = extSysProjectMapper.getCountByPagination(pr);
        responseVo.setRows(list);
        responseVo.setTotal(count.intValue());
        return responseVo;
    }

    @Override
    public void insertProjectConfig(ExtSysProject sysProject) {
        this.checkPrjCode(sysProject);
        sysProject.setGuid(UUID.randomUUID().toString());
//        Date datenow = new Date();
//        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        String createDate = df.format(datenow);
        try {
            sysProject.setCreateuser(SysUserUtils.getLoginAccount());
            sysProject.setCreatedate(new Date());
        } catch (Exception e) {
        }
        sysProject.setPcode(sysProject.getGuid());
        sysProject.setDelFlag("0");
        sysProjectMapper.insertSelective(sysProject);
        insertProjectToDataSourceBatch(sysProject);
        redisCacheProjectService.freshProjectServerTree();
    }


    private void checkPrjCode(ExtSysProject extSysProject) {
        String prjCode = extSysProject.getPrjCode();
        CommonAssert.notBlank(prjCode, "编码不能为空");
        List<SysProject> sysProjectList = extSysProjectMapper.selectByIdNeqPrjCode(extSysProject.getGuid(), prjCode);
        if (!sysProjectList.isEmpty()) {
            throw new RuntimeException("编码已存在, 请重新填写! ");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateProjectConfig(ExtSysProject sysProject) {
        this.checkPrjCode(sysProject);
        sysProjectMapper.updateByPrimaryKeySelective(sysProject);
        extSysProjectMapper.deleteProjectToDataSourceBatch(sysProject.getPcode());
        insertProjectToDataSourceBatch(sysProject);
        redisCacheProjectService.freshProjectServerTree();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteProjectConfig(List<String> list, String pcode) {
        // 查询到当前pcode下的数据源信息
        List<String> cfgDbList = extSysProjectMapper.selectDataSourceByPcode(pcode);
        // 将其保存到删除表中
        HashMap<String, Object> map = new HashMap<>();
        map.put("list", cfgDbList);
        map.put("project_code", pcode);
        extSysProjectMapper.insertProjectToDataSourceDelBatch(map);
        extSysPrjmenuMapper.deleteMenuByPcode(list);
        extSysProjectMapper.deleteProjectConfig(list);
        extSysProjectMapper.deleteProjectToDataSourceBatch(pcode);
        redisCacheProjectService.freshProjectServerTree();
    }

    @Override
    public List<SysProject> getProjectByPcode(String pcode) {
        return extSysProjectMapper.getProjectByPcode(pcode);
    }

    @Override
    public ExtSysProject getProjectConfigByGuid(String guid) {
        ExtSysProject sysProject = extSysProjectMapper.selectByGuid(guid);
        sysProject.setDataSource(extSysProjectMapper.selectDataSourceByPcode(sysProject.getPcode()));
        return sysProject;
    }

    @Override
    public List<ZTreeDataModelVo> getProjectTreeList() {
        List<ZTreeDataModelVo> ztreeList = new ArrayList<ZTreeDataModelVo>();
        List<SysProject> list = extSysProjectMapper.getAllProjectList();
        for (SysProject sysProject : list) {
            ZTreeDataModelVo ztmodelDataModelVo = new ZTreeDataModelVo();
            ztmodelDataModelVo.setId(sysProject.getPcode());
            ztmodelDataModelVo.setName(sysProject.getPname());
            ztmodelDataModelVo.setHint(sysProject.getPdesc());
            ztmodelDataModelVo.setIsMark("1");
            ztmodelDataModelVo.setPrjCode(sysProject.getPrjCode());
            ztreeList.add(ztmodelDataModelVo);
        }
        return ztreeList;
    }

    @Override
    public List<ZTreeDataModelVo> getProjectServerTreeList() {
        List<ZTreeDataModelVo> ztreeList = new ArrayList<ZTreeDataModelVo>();
        List<SysProject> list = extSysProjectMapper.getAllProjectList();
        for (SysProject sysProject : list) {
            ZTreeDataModelVo ztmodelDataModelVo = new ZTreeDataModelVo();
            ztmodelDataModelVo.setId(sysProject.getPcode());
            ztmodelDataModelVo.setName(sysProject.getPname());
            ztmodelDataModelVo.setHint(sysProject.getPdesc());
            ztmodelDataModelVo.setIsMark("1");
            List<PrjServiceExt> serverList =
                    extSysPrjserviceMapper.getServerByPcode(sysProject.getPcode());
            if (serverList != null && serverList.size() > 0) {
                List<ZTreeDataModelVo> ztreeserver = new ArrayList<ZTreeDataModelVo>();
                for (PrjServiceExt pjserver : serverList) {
                    ZTreeDataModelVo ztserver = new ZTreeDataModelVo();
                    ztserver.setId(pjserver.getServicecode());
                    ztserver.setName(pjserver.getServicename());
                    ztserver.setHint(pjserver.getServertype());
                    ztserver.setPagetype(pjserver.getServicetype());
                    ztserver.setIsMark("2");
                    ztreeserver.add(ztserver);
                }
                ztmodelDataModelVo.setChildren(ztreeserver);
            }
            ztreeList.add(ztmodelDataModelVo);
        }
        return ztreeList;
    }

    @Override
    public List<SysProjectExt> getProjectExtList() {
        return extSysProjectMapper.getAllProjectExtList();
    }

    /**
     * show 查询没有配置非结构化文档的项目信息 created by guoyanfei on 2018/04/17
     *
     * @return SysProject实体list集合
     */
    @Override
    public List<SysProject> selectPronotinDocument() {
        return extSysProjectMapper.getProjectNotinDocument();
    }

    @Override
    public List<CfgDb> selectDataSourceByProject(String pcode) {
        return extCfgDbMapper.selectDataSourceByProject(pcode);
    }

    @Override
    public List<SysProject> selectDataSourceByLoginName(String loginname) {
        return extSysProjectMapper.selectDataSourceByLoginName(loginname);
    }

    /**
     * 批量添加项目对应数据源
     *
     * @param sysProject
     */
    private void insertProjectToDataSourceBatch(ExtSysProject sysProject) {
        if (sysProject.getDataSource() != null && sysProject.getDataSource().size() > 0) {
            Map<String, Object> map = new HashMap<>();
            map.put("project_code", sysProject.getPcode());
            map.put("list", sysProject.getDataSource());
            if (dataBaseConnInfo.dataBaseType.equals("sqlite")) {
                extSysProjectMapper.insertProjectToDataSourceBatchSqlite(map);
            } else {
                extSysProjectMapper.insertProjectToDataSourceBatch(map);
            }
        }
    }
}
